/*
 * Copyright (c) 2010, VeRSI Consortium
 *   (Victorian eResearch Strategic Initiative, Australia)
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the VeRSI, the VeRSI Consortium members, nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package versi.vitro.oaiserviceprovider.service.exporter.impl;

import static java.lang.Boolean.TRUE;
import static versi.vitro.oaiserviceprovider.helper.Constant.AND_HARVEST_OUT_MODEL_NAME;
import static versi.vitro.oaiserviceprovider.helper.Constant.XSLT_LOCATION;

import java.io.ByteArrayOutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;

import org.apache.log4j.Logger;

import versi.vitro.oaiserviceprovider.application.Environment;
import versi.vitro.oaiserviceprovider.helper.GeneralHelper;
import versi.vitro.oaiserviceprovider.service.exporter.api.ExporterService;
import versi.vitro.oaiserviceprovider.service.jena.api.JenaService;
import versi.vitro.oaiserviceprovider.service.transformer.api.TransformerService;
import versi.vitro.oaiserviceprovider.service.validation.api.ValidationService;

/**
 * Service implementing {@link ExporterService}.
 */
public class ExporterServiceImpl implements ExporterService {

    /** log4j instance. */
    public static final Logger LOGGER = Logger.getLogger(ExporterServiceImpl.class);

    /** General Helper. */
    private GeneralHelper generalHelper;

    /** Validation Service. */
    private ValidationService validationService;

    /** Validation Service. */
    private TransformerService transformerService;

    /** Jena Service. */
    private JenaService jenaService;

    /** Byte Array representation of XSLT stylesheet. */
    private byte[] xslts;

    /** Export result should validate against given schemas. */
    private Boolean shouldValidateAgainstSchema = Environment.SHOULD_VALIDATE_AGAINST_SCHEMA;

    /**
     * Default Constructor.
     * 
     * @param generalHelper
     *            General Helper.
     * @param validationService
     *            Validation Service.
     * @param jenaService
     *            Jena Service.
     * @param transformerService
     *            TODO
     * 
     */

    public ExporterServiceImpl(GeneralHelper generalHelper, ValidationService validationService,
	    JenaService jenaService, TransformerService transformerService) {
	super();
	this.generalHelper = generalHelper;
	this.validationService = validationService;
	this.jenaService = jenaService;
	this.transformerService = transformerService;
	byte[] xsltBytes = readXsltResource();
	setXslts(xsltBytes);
    }

    public ExporterServiceImpl(GeneralHelper generalHelper, JenaService jenaService,
	    TransformerService transformerService) {
	super();
	this.generalHelper = generalHelper;
	this.validationService = null;
	this.jenaService = jenaService;
	this.transformerService = transformerService;
	byte[] xsltBytes = readXsltResource();
	setXslts(xsltBytes);
    }

    /**
     * Reads the XSLT stylesheet from a given location that is set within
     * properties file.
     */
    protected byte[] readXsltResource() {
	final String resource = generalHelper.readResourceAsString(XSLT_LOCATION);
	if (resource == null) {
	    throw new RuntimeException("Export service constructor was unable to obtain the XSLT file contents. ");
	}
	byte[] xsltBytes = resource.getBytes();
	return xsltBytes;
    }

    /** {@inheritDoc} */
    public void generateXmlFile() {

	byte[] rdfXml = extractRdfFromTripleStore();
	if (LOGGER.isInfoEnabled()) {
	    LOGGER.info("Step 7: RDF/XML has been extracted from triplestore!");
	}

	// System.out.println("generateXmlFile() step 1");

	byte[] resultByte = transformerService.applyXSLT(rdfXml, getXslts());
	if (LOGGER.isInfoEnabled()) {
	    LOGGER.info(new String(resultByte));
	    LOGGER.info("Step 8: RDF/XML has been transformed by style sheet!");
	}

	// System.out.println("generateXmlFile() step 2");
	boolean shouldWriteOutputFile = false;
	if (TRUE.equals(shouldValidateAgainstSchema)) {
	    shouldWriteOutputFile = validationService.validateAgainstSchemas(resultByte);
	    if (LOGGER.isInfoEnabled()) {
		LOGGER.info("Validation was successful!");
	    }
	} else {
	    shouldWriteOutputFile = true;
	    if (LOGGER.isInfoEnabled()) {
		LOGGER.info("Validation was skipped!");
	    }
	}

	// System.out.println("generateXmlFile() step 3");
	if (shouldWriteOutputFile) {
	    writeResult(resultByte);
	    if (LOGGER.isInfoEnabled()) {
		LOGGER.info("Result has been created on " + Environment.OUTPUT_LOCATION);
	    }
	}
    }

    /**
     * Gets the byte array that represent the content of andHarvestOut Model in
     * RDF/XML format.
     * 
     * @return
     */
    protected byte[] extractRdfFromTripleStore() {
	ByteArrayOutputStream baos = jenaService.getModelAsOutputStream(AND_HARVEST_OUT_MODEL_NAME, "RDF/XML");
	try {

	    // System.out.println("extract RDF from triple step 1");
	    OutputStreamWriter out;

	    out = new OutputStreamWriter(baos, "UTF-8");
	    // System.out.println("extract RDF from triple step 2");

	    // byte[] byteArray = out.toString().getBytes();
	    byte[] byteArray = baos.toString("UTF-8").getBytes();
	    // System.out.println("extract RDF from triple step 3");

	    // byte[] byteArray = baos.toByteArray();

	    LOGGER.info(new String(byteArray));
	    // System.out.println("extract RDF from triple step 4");
	    return byteArray;
	} catch (UnsupportedEncodingException e) {
	    // TODO Auto-generated catch block
	    e.printStackTrace();
	}
	// System.out.println("extract RDF from triple step 4");
	return null;

    }

    /**
     * 
     * @param resultByte
     */
    protected void writeResult(byte[] resultByte) {
	generalHelper.writeByteArrayToLocalFile(resultByte, Environment.OUTPUT_LOCATION);
    }

    /**
     * Sets the XSLT stylesheet.
     * 
     * @param xslts
     *            Byte array of XSLT to set.
     */
    private void setXslts(final byte[] xslts) {
	this.xslts = xslts;
    }

    /** {@inheritDoc} */
    public byte[] getXslts() {
	return xslts;
    }

    /**
     * True if result should be validate against schema, otherwise false.
     * 
     * @return boolean shouldValidateAgainstSchema.
     */
    public Boolean getShouldValidateAgainstSchema() {
	return shouldValidateAgainstSchema;
    }

    /**
     * Sets if schmea should be used to validate the result.
     * 
     * @param shouldValidateAgainstSchema
     *            to set.
     */
    public void setShouldValidateAgainstSchema(Boolean shouldValidateAgainstSchema) {
	this.shouldValidateAgainstSchema = shouldValidateAgainstSchema;
    }
}
